package com.zbj.homemade.mybatis;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * |                    .  ’   *   ‘  .
 * |               _6                    "     o0000o
 * |  o00o _    .%                         %. o0000000o
 * | o000000o.:                              :(0000000o
 * | o00000os                                  .000000o
 * |  o0000/     <b>不了不了,改需求真的伤身体</>   .000o
 * |    o0o                                       .0o
 * |     y        <b>我认为源代码,就是SkrSkr</>     .
 * |    y                                           ,
 * |   y          <b>小熊猫保佑,代码永不修改</>        ,
 * |   p                            .                 .
 * |   p                           @@.                .
 * |    y                        ;@@@;               .
 * |    \                       ;@@@@;.@.          ,;S
 * |     、                     .@@@@@@;       ,@@@@@
 * |     @\.            .****...*@@@@;     .@@@@@@@@@@@.
 * |    @@@@\.     . @@@@@@@@@@@@@@@;    .@@@@@@@@@@@@@@@.
 * |   @@@@@@@@@.@@@@@@@@@@@@@@@@;   .@@@@@@@@@@@@@@@@@@@@@.
 * |  @@@@@@..@@@@..@@@@@@..@@@@@ .@@...@@@@@..@@..@@@@@..@@.
 * | @@@@@@@@..@..@@@@@@@@@@@@@;.@@@..@..@@@..@@....@@@..@@@@.
 * |@y@@@@@@@@..@@@@@@@@..@@@@i@@@@..@@@..@..@@..@@..@..@@@@n@.
 * |@n@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@...@@..@@@@...@@@@@n@@.
 * |@@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@@@.@@..@@@@@..@@@@@@@@@@.
 * |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
 *
 *
 * ArrayBlockingQueue数组的获取方向
 * 是回环式的
 *
 * 例如 数组中有4个元素 获取游标方向: 0 -> 1 -> 2 -> 3 -> 0 -> 1......
 *
 *  在队列中，无论是否有元素，皆占有队列位置资源，所以有notFull,notEmpty两种等待方式
 *
 *
 **/
public class MyArrayBlockingQueue<T> {

    //队列元素
    private Object[] items;
    //队列容积
    private final int capicity;
    //put index 插入游标
    private int putIndex;
    //take index 获取游标
    private int takeIndex;
    //计数器 当前队列元素数量
    private int counter;
    //可重入锁
    private Lock lock;
    //非满 满了就等待
    private Condition notFull;
    //非空 空了就等待
    private Condition notEmpty;

    public MyArrayBlockingQueue(int capicity) {

        this.capicity = capicity;

        this.items = new Object[capicity];

        lock = new ReentrantLock();

        this.notFull = this.lock.newCondition();

        this.notEmpty = this.lock.newCondition();
    }

    //阻塞获取
    public T take() throws InterruptedException {

        //可打断锁
        this.lock.lockInterruptibly();

        try {
            //当队列中没有任何元素时
            while (counter == 0)
                notEmpty.await();

            return deque();

        } finally {
            lock.unlock();
        }
    }

    //阻塞插入
    public T put() throws InterruptedException {

        //可打断锁
        this.lock.lockInterruptibly();

        try {
            //当队列中没有任何元素时
            while (counter == 0)
                notEmpty.await();

            return deque();

        } finally {
            lock.unlock();
        }
    }

    //出队 (必须在锁下使用)
    private T deque() {

        //取元素
        T item = (T) items[takeIndex];

        //删除队列中元素
        items[takeIndex] = null;

        //当游标到队尾时，重置游标
        if (++takeIndex == items.length)
            takeIndex = 0;

        //总和-1
        counter--;

        //唤醒非满等待
        notFull.signal();

        return item;
    }

    //入队 (必须在锁下使用)
    private void enque(T item){

        items[putIndex] = item;

        if (++putIndex == items.length)
            putIndex = 0;

        counter++;

        notEmpty.signal();
    }
}
